home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ETO Development Tools 4
/
ETO Development Tools 4.iso
/
Tools - Objects
/
MacApp
/
MacApp 3.0a2
/
Libraries
/
UTEView.cp
< prev
next >
Wrap
Text File
|
1991-05-01
|
66KB
|
2,408 lines
// UTEView.cp
// Copyright © 1984-1991 Apple Computer Inc. All rights reserved.
//--------------------------------------------------------------------------------------------------
#ifndef __STDIO__
#include <StdIo.h>
#endif
#ifndef __UGEOMETRY__
#include <UGeometry.h>
#endif
#ifndef __ULIST__
#include <UList.h>
#endif
#ifndef __ALIASES__
#include <Aliases.h>
#endif
#ifndef __UFILE__
#include <UFile.h>
#endif
#ifndef __EDITIONS__
#include <Editions.h>
#endif
#ifndef __DIALOGS__
#include <Dialogs.h>
#endif
#ifndef __UAPPLICATION__
#include <UApplication.h>
#endif
#ifndef __UDOCUMENT__
#include <UDocument.h>
#endif
#ifndef __USCROLLER__
#include <UScroller.h>
#endif
#ifndef __SCRAP__
#include <Scrap.h>
#endif
#ifndef __UCLIPBOARDMGR__
#include <UClipboardMgr.h>
#endif
#ifndef __UPRINTHANDLER__
#include <UPrintHandler.h>
#endif
#ifndef __UFAILURE__
#include <UFailure.h>
#endif
#ifndef __UMACAPPUTILITIES__
#include <UMacAppUtilities.h>
#endif
#ifndef __UPATCH__
#include <UPatch.h>
#endif
#ifndef __UMEMORY__
#include <UMemory.h>
#endif
#ifndef __UMACAPPGLOBALS__
#include <UMacAppGlobals.h>
#endif
#ifndef __UERRORMGR__
#include <UErrorMgr.h>
#endif
#ifndef __MENUS__
#include <Menus.h>
#endif
#ifndef __UMENUMGR__
#include <UMenuMgr.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __PACKAGES__
#include <Packages.h>
#endif
#ifndef __FONTS__
#include <Fonts.h>
#endif
#ifndef __SCRIPT__
#include <Script.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
#ifndef __UTECOMMANDS__
#include <UTECommands.h>
#endif
#include "UTEView.h"
//--------------------------------------------------------------------------------------------------
ProcPtr gDefClikLoopProc; // Standard TextEdit click loop routine
/* The following are considered private, but appear in the interface in case you need to
override a method that uses one of these. */
TTEView* pCurrTEView;
#if qDebug
Boolean pTEIntenseDebugging; // For the benefit of ClikLoopForTTEView only
#endif
//--------------------------------------------------------------------------------------------------
#pragma segment TEInit
pascal void InitUTEView(void)
{
if (qTemplateViews)
{
// So linker doesn't strip TTEView class
DontDeadStrip(TTEView);
RegisterStdType("TTEView", kStdTEView);
}
gUTEViewInitialized = TRUE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEDebug
const short kMaxIndex = 2047;
typedef char x[kMaxIndex];
typedef x* XPtr;
typedef XPtr* XHandle;
void WriteChar(short index,
Handle hText)
{
if (index <= kMaxIndex)
fprintf(stderr, "[%1d:%1d]", index, *((XHandle)hText)[index]);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEDebug
pascal void DumpTERecord(TEHandle aTEH)
{
const short kMaxCharsToPrint = 100;
short size;
fprintf(stderr, "TE -- dest rect: ");
WriteRect((**aTEH).destRect);
fprintf(stderr, "\n");
size = (**aTEH).teLength;
fprintf(stderr, "Line ht: %1d", (**aTEH).lineHeight);
fprintf(stderr, "; teLength: %1d", size);
fprintf(stderr, "; hText length: %1d", GetHandleSize((**aTEH).hText));
fprintf(stderr, "; lines: %1d", (**aTEH).nLines);
fprintf(stderr, "\n");
if (gIntenseDebugging)
{
Handle hText = (**aTEH).hText;
fprintf(stderr, "Chars: ");
for (short i = 0; i <= Min(kMaxCharsToPrint, Min(2047, size - 1)); ++i)
{
WriteChar(i, hText);
if (i % 10 == 9)
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
fprintf(stderr, "InPort vis bbox: ");
WriteRect((**((**aTEH).inPort->visRgn)).rgnBBox);
fprintf(stderr, "; clip bbox: ");
WriteRect((**((**aTEH).inPort->clipRgn)).rgnBBox);
fprintf(stderr, "\n");
if ((**aTEH).inPort != qd.thePort)
{
fprintf(stderr, "thePort vis bbox: ");
WriteRect((**(qd.thePort->visRgn)).rgnBBox);
fprintf(stderr, "; clip bbox: ");
WriteRect((**(qd.thePort->clipRgn)).rgnBBox);
fprintf(stderr, "\n");
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void SetSelect(short theStart,
short theEnd,
TEHandle hTE)
{
(**hTE).selStart = theStart;
(**hTE).selEnd = theEnd;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal Boolean ClickLoopForTTEView(void)
{
if (pCurrTEView != NULL)
return pCurrTEView->ClikLoop();
else
return TRUE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEOpen
pascal void TTEView::Initialize(void) // override
{
inherited::Initialize();
#if qDebug
if (!gUTEViewInitialized)
{
ProgramBreak("InitUTEView must be called before creating a TE View.");
Failure(noErr, 0);
}
#endif
#if qDebug
pTEIntenseDebugging = FALSE;
#endif
fHTE = NULL;
fText = NULL;
fSavedTEHandle = NULL;
fInset = gZeroVRect;
fKeyCmdNumber = cTyping;
fMaxChars = kUnlimited;
fLastHeight = 0;
fLastWidth = 0;
fTypingCommand = NULL;
fTextStyle = gSystemStyle;
fJustification = teFlushDefault;
fAcceptsChanges = TRUE; /* Stuff to FALSE if you don't want to allow
Cut, Paste, or Typing */
//!!! put these in the template after 2.0 !!!
// fControlChars = [chLeft, chRight, chUp, chDown, chBackspace, chReturn];
fControlChars = ASSETELEM(chLeft) | ASSETELEM(chRight) |
ASSETELEM(chUp) | ASSETELEM(chDown) |
ASSETELEM(chBackspace) | ASSETELEM(chReturn);
fMinAhead = kMinAhead;
fStyleType = kWithStyle;
fAutoWrap = TRUE;
fFreeText = TRUE;
fSpecsChanged = FALSE;
fLastPageBreak = 0;
fLastLine = 0;
fSelAnchor = 0;
fUpDown = FALSE;
fCursorID = iBeamCursor;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEOpen
pascal void TTEView::ITEView(TDocument* itsDocument,
TView* itsSuperView,
const VPoint& itsLocation,
const VPoint& itsSize,
SizeDeterminer itsHDeterminer,
SizeDeterminer itsVDeterminer,
const VRect& itsInset,
const TextStyle& itsTextStyle,
short itsJustification,
Boolean itsStyleType,
Boolean itsAutoWrap)
{
this->IView(itsDocument, itsSuperView, itsLocation, itsSize, itsHDeterminer, itsVDeterminer);
fInset = itsInset;
fTextStyle = itsTextStyle;
fJustification = itsJustification;
fStyleType = itsStyleType;
fAutoWrap = itsAutoWrap;
this->MakeTERecord();
fSelAnchor = (*fHTE)->selStart;
SetClikLoop(&ClickLoopForTTEView, fHTE); // (*fHTE)->clikLoop = &ClickLoopForTTEView;
// ??? Things don't work well if fText is non-NULL. Is this the way to solve it?
fText = (*fHTE)->hText;
this->SetIdleFreq(0); // Idle ASAP
this->AddAdorner(gSelectionAdorner, kViewAdornPriority, FALSE); // Wants DoHighlightSelection called
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEOpen
pascal void TTEView::IRes(TDocument* itsDocument,
TView* itsSuperView,
Ptr& itsParams) // override
{
TextStyle aTextStyle;
VRect vr;
inherited::IRes(itsDocument, itsSuperView, itsParams);
TEViewTemplate& templateData = *((TEViewTemplate *) itsParams);
{
fTypingCommand = NULL;
fLastHeight = 0;
fLastWidth = 0;
fSpecsChanged = FALSE;
vr = templateData.itsInset;
fInset = vr;
fKeyCmdNumber = templateData.itsKeyCmdNumber;
fMaxChars = templateData.itsMaxChars;
SetTextStyle(aTextStyle, GetFontNum(templateData.itsFontName), templateData.itsTextFace, templateData.itsTextSize, templateData.itsTextColor);
fTextStyle = aTextStyle;
fJustification = templateData.itsJustification;
fAcceptsChanges = templateData.itsAcceptsChanges;
fStyleType = templateData.itsStyleType;
fAutoWrap = templateData.itsAutoWrap;
fFreeText = templateData.itsFreesText;
this->MakeTERecord();
fSelAnchor = (**fHTE).selStart;
SetClikLoop(&ClickLoopForTTEView, fHTE);// (*fHTE)->clikLoop = &ClickLoopForTTEView;
fText = (**fHTE).hText;
this->SetIdleFreq(0); // Idle ASAP
}
OffsetPtrWStr(itsParams, sizeof(TEViewTemplate));
this->AddAdorner(gSelectionAdorner, kViewAdornPriority, FALSE); // Wants DoHighlightSelection called
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal TObject* TTEView::Clone(void) // override
{
TTEView * aClonedTTEView;
TEStyleHandle inputStyles;
TEStyleHandle theStyles;
TEStyleHandle oldStyles;
STHandle inputElements;
STHandle theElements;
STHandle oldElements;
LHHandle theLineHeights;
LHHandle oldLineHeights;
NullStHandle theNullStyles;
Handle theText;
aClonedTTEView = (TTEView *)(inherited::Clone());
if (this->fHTE != NULL)
{
HLock((Handle)(this->fHTE));
if (this->fStyleType == kWithStyle)
aClonedTTEView->fHTE = TEStylNew((**(this->fHTE)).destRect, (**(this->fHTE)).viewRect);
else
aClonedTTEView->fHTE = TENew((**(this->fHTE)).destRect, (**(this->fHTE)).viewRect);
SetClikLoop(&ClickLoopForTTEView, aClonedTTEView->fHTE);
// Clone the styles record since clone or stuffstyles doesn't do it for us
if (this->fStyleType == kWithStyle)
{
this->ExtractStyles(inputStyles, inputElements);
oldStyles = GetStylHandle(aClonedTTEView->fHTE);
theNullStyles = (**oldStyles).nullStyle;
oldElements = (**oldStyles).styleTab;
oldLineHeights = (**oldStyles).lhTab;
oldElements = (STHandle)(DisposeIfHandle((Handle)oldElements));
oldLineHeights = (LHHandle)(DisposeIfHandle((Handle)oldLineHeights));
theStyles = inputStyles;
FailOSErr(HandToHand((Handle&)theStyles));
theElements = inputElements;
FailOSErr(HandToHand((Handle&)theElements));
theLineHeights = (**inputStyles).lhTab;
FailOSErr(HandToHand((Handle&)theLineHeights));
(**theStyles).nullStyle = theNullStyles;// Replace null style handle
(**theStyles).lhTab = theLineHeights;// Replace line heights table handle
(**theStyles).styleTab = theElements;// Replace STElements handle
// NOTE!! SetStylHandle will dispose of oldStyles for us!
SetStylHandle(theStyles, aClonedTTEView->fHTE);
}
aClonedTTEView->fSavedTEHandle = (**(aClonedTTEView->fHTE)).hText;// Save existing handle
theText = this->fText;
FailOSErr(HandToHand((Handle&)theText));
(**(aClonedTTEView->fHTE)).hText = theText;// Install new handle
aClonedTTEView->fText = theText; // Make a local copy, too
//!!! Note SIze->short cast
(**(aClonedTTEView->fHTE)).teLength = (short)GetHandleSize((**(aClonedTTEView->fHTE)).hText);// Tell TE how long we are
if (aClonedTTEView->fStyleType == kWithStyle) // Fix for styled TE. Yuk.
(**theStyles).runs[0].startChar = (**(aClonedTTEView->fHTE)).teLength++;
HUnlock((Handle)(this->fHTE));
}
aClonedTTEView->RecalcText();
aClonedTTEView->fTypingCommand = NULL;
return aClonedTTEView;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteRes
pascal void TTEView::WRes(ViewRsrcHandle theResource,
Ptr& itsParams) // override
{
Str255 theFont;
VRect vr;
Rect r;
inherited::WRes(theResource, itsParams);
GetFontName(fTextStyle.tsFont, theFont);
TEViewTemplate& templateData = *((TEViewTemplate *) ExpandPtrWStr((Handle)theResource, itsParams, sizeof(TEViewTemplate), theFont.Length()));
templateData.itsStyleType = fStyleType;
templateData.itsAutoWrap = fAutoWrap;
templateData.itsAcceptsChanges = fAcceptsChanges;
templateData.itsFreesText = fFreeText;
templateData.itsKeyCmdNumber = (short)fKeyCmdNumber;//!!! Note long->short cast
templateData.itsMaxChars = fMaxChars;
vr = fInset;
r = vr;
templateData.itsInset = r;
templateData.itsJustification = fJustification;
templateData.itsTextFace = fTextStyle.tsFace;
templateData.itsTextSize = fTextStyle.tsSize;
templateData.itsTextColor = fTextStyle.tsColor;
// itsFontName = theFont;
CopyStr255(theFont, PRStr(templateData.itsFontName));
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteRes
pascal void TTEView::WriteRes(ViewRsrcHandle theResource,
Ptr& itsParams) // override
{
gWResSignature = 'tevw';
gWResType = "TTEView";
this->WRes(theResource, itsParams);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEClose
pascal void TTEView::Free(void) // override
{
if (fHTE != NULL)
{
if (fSavedTEHandle != NULL)
{
// Worry about fText separately. Put back
(**fHTE).hText = fSavedTEHandle; // …the handle which TE allocated
(**fHTE).teLength = // This is here because it only makes
(short)GetHandleSize((**fHTE).hText);//!!! Note Size->short cast
if (fFreeText) // …sense if fSavedTEHandle is not NULL.
fText = DisposeIfHandle(fText);
fText = NULL; // Always drop my reference
}
TEDispose(fHTE);
fHTE = NULL;
fSavedTEHandle = NULL;
}
inherited::Free();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::Activate(Boolean entering) // Override
{
inherited::Activate(entering);
if (entering)
{
if (fHTE)
{
if (fIdleFreq == kMaxIdleTime)
this->SetIdleFreq(0); // Idle ASAP
SetKeyScript(Font2Script(fTextStyle.tsFont));
this->SetActive(TRUE);
pCurrTEView = this; // So the global clikLoop routine can forward
}
}
else
{
this->SetActive(FALSE);
this->DoneTyping();
fSpecsChanged = TRUE;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::DoHighlightSelection(HLState fromHL,
HLState toHL) // Override
{
if (fHTE)
{
/*
if ((toHL == hlOn) && (TEFeatureFlag(teFOutlineHilite, TEBitTest, fHTE) == TEBitSet))
TEFeatureFlag(teFOutlineHilite, TEBitSet, fHTE);
if ((toHL == hlDim) || (fromHL == hlDim))
TEFeatureFlag(teFOutlineHilite, TEBitSet, fHTE);
else
TEFeatureFlag(teFOutlineHilite, TEBitClear, fHTE);
*/
/*
switch (fromHL + toHL)
{
// case hlOffOn:
case hlOnOff:
TEFeatureFlag(teFOutlineHilite, TEBitClear, fHTE);
break;
// case hlOffDim:
case hlDimOff:
// case hlDimOn:
case hlOnDim:
TEFeatureFlag(teFOutlineHilite, TEBitSet, fHTE);
break;
}
*/
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::BecameWindowTarget(void) // Override
{
if (fHTE)
{
if (fIdleFreq == kMaxIdleTime)
this->SetIdleFreq(0); // Idle ASAP
SetKeyScript(Font2Script(fTextStyle.tsFont));
this->DoHighlightSelection(hlDim,hlOn);
this->SetActive(TRUE);
pCurrTEView = this; // So the global clikLoop routine can forward
}
inherited::BecameWindowTarget();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::BecameApplicationTarget(void) // Override
{
/* if (fHTE)
{
if (fIdleFreq == kMaxIdleTime)
this->SetIdleFreq(0); // Idle ASAP
SetKeyScript(Font2Script(fTextStyle.tsFont));
// this->DoHighlightSelection(hlDim,hlOn);
this->SetActive(TRUE);
pCurrTEView = this; // So the global clikLoop routine can forward
}
*/
inherited::BecameApplicationTarget();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal Boolean TTEView::ClikLoop()
{
VPoint viewPt;
Rect visRect;
VPoint delta;
short lead;
short trail;
TScroller * scroller;
Point msePt;
if (StillDown())
{
scroller = this->GetScroller(FALSE);
if ((scroller != NULL) && scroller->Focus())
{
GetMouse(msePt);
scroller->QDToViewPt(msePt, viewPt);
scroller->AutoScroll(viewPt, delta);// find how much should scroll
if (this->Focus())
{
this->GetVisibleQDRect(visRect);
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
{
lead = (short)(fLocation[vhs] - visRect[topLeft][vhs]);//!!! long->short cast
trail = (short)(fLocation[vhs] + fSize[vhs] - visRect[botRight][vhs]);//!!! long->short cast
if (delta[vhs] < 0)
{
// !!!FIX the following 2 lines after MPW C compiler bug is corrected.
long temp = Min(Max(delta[vhs], lead), 0);
delta[vhs] = temp;
}
else
{
// !!!FIX the following 2 lines after MPW C compiler bug is corrected.
long temp1 = Max(Min(delta[vhs], trail), 0);
delta[vhs] = temp1;
}
}
/* The intent of the above is not to do autoscrolling that would scroll
beyond the subview boundary in any direction */
if (delta != gZeroVPt)
{
scroller->ScrollBy(delta, kRedraw);
this->Update(); // make sure the scrolling was visible
}
}
}
/* Focus may have changed, which could change lots of things, thus
requiring us, tiresomely, to take some or all of the following
restorative precautions b/c clikloop expects us to be clipped to the
destrect. */
if (this->Focus())
this->ClipFurtherTo((**fHTE).destRect, 0, 0);
}
return TRUE; // Still consider the mouse to be down
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::AutoScrolling(Boolean doScrolling)
{
if (fHTE != NULL)
TEAutoView(doScrolling, fHTE);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::BeInPort(GrafPtr itsPort) // override
{
if (fHTE != NULL)
{
if (itsPort == NULL)
(**fHTE).inPort = gWorkPort;
else
(**fHTE).inPort = itsPort;
if (itsPort == NULL)
{
this->DoneTyping();
fSpecsChanged = TRUE;
}
}
inherited::BeInPort(itsPort);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::BeInScroller(TScroller* itsScroller)// override
{
short vertScrollUnit;
if ((fHTE != NULL) && (itsScroller != NULL))
{
if ((**fHTE).lineHeight > 0) // This works for both old && new TextEdit
vertScrollUnit = (**fHTE).lineHeight;
else
vertScrollUnit = GetDefFontSize(); // Ask for system default size
itsScroller->SetScrollParameters(VPoint(vertScrollUnit, kStdScrollUnit), FALSE, TRUE);
}
inherited::BeInScroller(itsScroller);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::CalcMinSize(VPoint& minSize)// override
{
/* Note that we omit the margins here, so that if TView.ComputeExtent rounds up to a
page multiple, the margins will get tacked on after. Also, insure we don't run off
the end of the coordinate system if there are many lines of text. */
minSize = VPoint(Min(kMaxCoord, this->CalcRealHeight()), fSize.h - fInset.left - fInset.right);
if ((fSizeDeterminer[hSel] == sizeVariable) &&!fStyleType &&!fAutoWrap)
minSize = VPoint(minSize.v, fLastWidth);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal long TTEView::CalcRealHeight(void)
{
Boolean lastIsCR;
short theMode;
long theHeight;
TextStyle theStyle;
FontInfo theFontInfo;
short theFontHeight;
TERec & theTERec = **fHTE;
lastIsCR = (theTERec.teLength <= 0) || ((*(CharsHandle)(theTERec.hText))[theTERec.teLength - 1] == chReturn);
if (fStyleType == kWithStyle)
{
theHeight = 0;
if (theTERec.nLines > 0)
theHeight = TEGetHeight(MAXINT, 0, fHTE);
if (lastIsCR) // then can't use TEGetHeight so we
{
// …have to figure it out ourselves.
theMode = doAll;
lastIsCR = this->ContinuousStyle(MAXINT, MAXINT, theMode, theStyle);
GetTextStyleFontInfo(theStyle, theFontInfo, theFontHeight);
theHeight = theHeight + theFontHeight;
}
}
else
{
theHeight = theTERec.nLines + (long)(lastIsCR);
theHeight = theHeight * theTERec.lineHeight;
}
#if qDebugMsg
if (gIntenseDebugging)
fprintf(stderr, "CalcRealHeight=%1d\n", theHeight);
#endif
return theHeight;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal long TTEView::CalcRealWidth(void)
{
short fromChar;
short toChar;
short aWidth;
TextStyle theStyle;
SignedByte savedState;
aWidth = 0;
/* !!! it would be nice to compute this for styled TE but TEGetPoint only returns the bottom
left of the character box so it can't be used to find the width including last character
in a line. And since some characters can change width based on context we can't just
measure the last character and add it in. Maybe we can makeup an formula based on
style runs or something eventually. */
if (!fStyleType)
{
if (this->Focus())
{
theStyle = fTextStyle;
SetPortTextStyle(theStyle);
aWidth = 0;
fromChar = (**fHTE).lineStarts[0];
savedState = LockHandleHigh((Handle)(**fHTE).hText);
for (short index = 1; index <= (**fHTE).nLines; ++index)
{
toChar = (**fHTE).lineStarts[index] - 1;
aWidth = (short)Max(aWidth, TextWidth(*((**fHTE).hText), fromChar, (toChar - fromChar) + 1));//!!! long->short cast
fromChar = toChar + 1;
}
HSetState((Handle)(**fHTE).hText, savedState);
return aWidth;
}
}
else if (qDebug)
ProgramBreak("IN TTEView.CalcRealWidth: called for a styled TE Record");
return aWidth;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::ChangeWrap(Boolean newAutoWrap,
Boolean redraw)
{
fAutoWrap = newAutoWrap;
if (newAutoWrap)
(**fHTE).crOnly = 0;
else
(**fHTE).crOnly = -1;
if (redraw)
{
this->RecalcText();
this->SynchView(kRedraw);
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal Boolean NeedAdjust(SizeDeterminer aSizeDeterminer)
{
return !((aSizeDeterminer == sizeFixed) || (aSizeDeterminer == sizeSuperView) || (aSizeDeterminer == sizeRelSuperView));
}
pascal void TTEView::ComputeSize(VPoint& newSize)// override
{
inherited::ComputeSize(newSize);
if (NeedAdjust(fSizeDeterminer[hSel])) // If necessary, tack on the margins
newSize.h = Min(kMaxCoord, newSize.h + fInset.left + fInset.right);
if (NeedAdjust(fSizeDeterminer[vSel]))
newSize.v = Min(kMaxCoord, newSize.v + fInset.top + fInset.bottom);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::CalcSelLoc(VRect& selectionRect)
{
const short kSlopToAllow = 36;
CharsHandle handleToText;
short startOfSelection;
short endOfSelection;
short charCount;
short lineHeight;
short fontAscent;
TextStyle theStyle;
Boolean selectionIsTheLastReturn;
short theMode;
FontInfo theFontInfo;
short theFontHeight;
VPoint temp;
VPoint temp1;
{
TERec& theTERec = **fHTE;
charCount = theTERec.teLength;
startOfSelection = theTERec.selStart;
endOfSelection = theTERec.selEnd;
handleToText = (CharsHandle)(theTERec.hText);
if ((theTERec.selEnd - theTERec.selStart == 0) && (fIdleFreq == kMaxIdleTime))
this->SetIdleFreq(0); // Idle ASAP
}
selectionIsTheLastReturn = (startOfSelection == charCount) && (charCount > 0) && ((*handleToText)[charCount - 1] == chReturn);
// !!!FIX the following 2 lines after MPW C compiler bug is corrected.
this->OffsetToPt(startOfSelection, temp);
selectionRect[topLeft] = temp;
// OffsetToPt returns the baseline point. Correct for the lineheight
TEGetStyle(startOfSelection, theStyle, lineHeight, fontAscent, fHTE);
selectionRect.top = selectionRect.top - lineHeight;
// !!!FIX the following 2 lines after MPW C compiler bug is corrected.
this->OffsetToPt(endOfSelection, temp1);
selectionRect[botRight] = temp1;/* Darn! wish we could know where the
point to the bottom right of an offset
is!!! This way we can't ever return the
"real" rectangle that encloses the
selection. */
if (selectionIsTheLastReturn)
{
theMode = doAll;
// Get the style so we know how tall to make the selection when its just the last return
this->ContinuousStyle(MAXINT, MAXINT, theMode, theStyle);
GetTextStyleFontInfo(theStyle, theFontInfo, theFontHeight);
selectionRect.top = selectionRect.bottom;
selectionRect.bottom += theFontHeight;
}
else
{
/* Correct errors by CalcSelLoc. If there is no selection then the "selection" consists of
the bits enclosed by the insertion bar. */
if (((**fHTE).selEnd - (**fHTE).selStart) == 0)
selectionRect.left = selectionRect.right - 1;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal Boolean TTEView::ContinuousStyle(short firstChar,
short lastChar,
short& mode,
TextStyle& aStyle)
{
short oldSelStart;
short oldSelEnd;
Boolean result;
oldSelStart = (**fHTE).selStart;
oldSelEnd = (**fHTE).selEnd;
SetSelect(firstChar, lastChar, fHTE); // Use SetSelect so this is invisible
result = TEContinuousStyle(mode, aStyle, fHTE);
SetSelect(oldSelStart, oldSelEnd, fHTE);
return result;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal Boolean TTEView::ContainsClipType(ResType aType)// override
{
return (aType == 'TEXT');
}
//--------------------------------------------------------------------------------------------------
// Put in resident segment since this gets called while typing
#pragma segment TERes
pascal VCoordinate TTEView::DoBreakFollowing(VHSelect vhs,
VCoordinate prevBreak,
Boolean& automatic)// override
{
VHSelect orthoVhs;
short possibleLoc;
TEStyleHandle theStyles;
LHHandle lhTab;
short height;
short lineHeight;
short lineNo;
orthoVhs = gOrthogonal[vhs];
automatic = TRUE;
possibleLoc = (short)Min(kMaxCoord, prevBreak + fPrintHandler->fViewPerPage[orthoVhs]); //!!! long->short
/* We want to get rid of the on-screen margin represented by fMargin when printing, so
adjust things so that the portion of the view occupied by the screen margin doesn't
get printed. */
if (prevBreak == 0)
possibleLoc += (short)fInset[topLeft][orthoVhs]; //!!! long->short
if ((fStyleType == kWithStyle) && (vhs == hSel))
{
if (fLastPageBreak == prevBreak)
{
height = fLastPageBreak;
lineNo = fLastLine;
}
else
{
height = (short)fInset[topLeft][orthoVhs]; //!!! VCoordinate->short
lineNo = 0;
}
theStyles = GetStylHandle(fHTE);
lhTab = (**theStyles).lhTab;
while (lineNo < (**fHTE).nLines)
{
lineHeight = (*lhTab)[lineNo].lhHeight;
if (height + lineHeight <= possibleLoc)
height += lineHeight;
else
break;
++lineNo;
}
if (lineNo >= (**fHTE).nLines)
possibleLoc = (short)Max(possibleLoc, height); //!!! long->short
else
possibleLoc = height;
fLastPageBreak = possibleLoc;
fLastLine = lineNo;
}
if ((possibleLoc + fInset[topLeft][orthoVhs]) >= fSize[orthoVhs])
return fSize[orthoVhs];
else
return possibleLoc;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::DoCalcViewPerPage(VPoint& viewPerPage)// override
{
inherited::DoCalcViewPerPage(viewPerPage); // Get max amount allowed given margins
#if qDebugMsg
if (gDebugPrinting)
{
fprintf(stderr, "TTEView: incoming generic viewPerPage:");
WriteVPt(viewPerPage);
fprintf(stderr, "\n");
}
#endif
if ((fStyleType != kWithStyle) && (fHTE != NULL))// Adjust for integral # of lines per page
viewPerPage.v = (**fHTE).lineHeight * (viewPerPage.v / (**fHTE).lineHeight);
#if qDebug
if (gDebugPrinting)
{
fprintf(stderr, "TTEView: computed viewPerPage:");
WriteVPt(viewPerPage);
fprintf(stderr, "\n");
}
#endif
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal Boolean TTEView::DoIdle(IdlePhase phase) // override
{
if (phase == idleContinue)
if ((fHTE != NULL) && ((**fHTE).selEnd - (**fHTE).selStart == 0) && this->IsEnabled())
{
if (fAcceptsChanges && this->IsDrawable())
TEIdle(fHTE);
this->SetIdleFreq(Max(GetCaretTime() / 2, 1));/* Reset idle frequency in case user changed
it*/
}
else
this->SetIdleFreq(kMaxIdleTime); // No need to bother anyone.
return FALSE; // Didn't free myself
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::DoKeyCommand(TToolboxEvent* event)// override
/* The Tab character has no width in some fonts, and so can cause confusing screen feedback.
It is filtered out by default. If you want to include it in your text union it into fControlChars. */
{
TTETypingCommand * aTypingCommand = NULL;
Boolean needNewCommand = FALSE;
Boolean handledCharacter = FALSE;
Boolean selecting = FALSE;
short goToPos = (**fHTE).selStart;
short i = 0;
short nonAnchor;
Boolean expanding;
short newStart;
short newEnd;
Boolean towardStart;
VPoint aVPoint;
unsigned char ch = event->fCharacter;
if (this->IsEnabled()) // if view is not enabled then we don't take ANY keystrokes
{
if ((ch >= ' ') || IN(fControlChars, ASSETELEM(ch))) // Check that the character should be accepted
{
if (((ch == chLeft) || (ch == chRight) || (ch == chUp) || (ch == chDown)) && this->Focus()) // check for pure movement keys
{
this->DoneTyping(); // Like mousedown, further typing == new cmd
fSpecsChanged = TRUE;
//################
if ((ch != chUp) && (ch != chDown))
fUpDown = FALSE;
if ((ch == chLeft) || (ch == chRight))
{
towardStart = (ch == chLeft);
if (GetScript((short)GetEnvirons(smKeyScript), smScriptRight) != 0)//!!! long->short
towardStart =!towardStart;
}
else
towardStart = FALSE;
{
TERec& theTERec = **fHTE; //Pascal: WITH (**fHTE)
if (theTERec.selStart == theTERec.selEnd)
fSelAnchor = theTERec.selStart;
if (fSelAnchor < 0)
if ((ch == chUp) || (towardStart))
fSelAnchor = theTERec.selEnd;
else
fSelAnchor = theTERec.selStart;
if (fSelAnchor == theTERec.selEnd)
nonAnchor = theTERec.selStart;
else
nonAnchor = theTERec.selEnd;
}
if ((ch == chUp) && (this->OffsetToLine(nonAnchor) == 0))
{
//same as Cmd-Up
selecting = event->fShiftKey;
handledCharacter = TRUE;
goToPos = 0;
fUpDown = FALSE;
}
else if ((ch == chDown) && (this->OffsetToLine(nonAnchor) == (**fHTE).nLines - 1))
{
//same as Cmd-Down
selecting = event->fShiftKey;
handledCharacter = TRUE;
goToPos = (**fHTE).teLength;
fUpDown = FALSE;
}
if ((!handledCharacter) && (ch >= chLeft) && (ch <= chDown))
{
HLock((Handle)fHTE);
selecting = event->fShiftKey;
handledCharacter = TRUE;
if (event->fCmdKey) // Actually, Cmd-Up && Cmd-Down differ from
{ // the Human Interface Guidelines. Let me
if (ch == chUp)
goToPos = 0; /* know if you think this should be
modified!*/
else if (ch == chDown)
goToPos = (**fHTE).teLength;
else if (towardStart)
goToPos = this->OffsetToLineStart(nonAnchor);
else
goToPos = this->OffsetToLineEnd(nonAnchor);
fUpDown = FALSE;
}
else if ((ch == chUp) || (ch == chDown))
{
if (!fUpDown)
{
VPoint aVPoint;
fUpDown = TRUE;
OffsetToPt(nonAnchor, aVPoint);
fUpDownH = (short)aVPoint.h; //!!! VCoordinate->short
}
if ((**fHTE).lineHeight < 0)//styled text
{
i = this->OffsetToLine(nonAnchor);
i = (short)TEGetHeight(((long)i), ((long)i), fHTE);//!!! long->short
}
else
i = (**fHTE).lineHeight;
if (ch == chUp)
i = -i;
this->OffsetToPt(nonAnchor, aVPoint);
aVPoint.v += i;
aVPoint.h = fUpDownH;
goToPos = this->PtToOffset(aVPoint);
i = this->OffsetToLine(nonAnchor);
if ((ch == chUp) && (goToPos == (**fHTE).lineStarts[i]))
--goToPos;
else if ((ch == chDown) && (this->OffsetToLine(goToPos) == i + 2))
++goToPos;
}
else if (event->fOptionKey /*& ((ch == chLeft) || (ch == chRight))*/)
{
if (selecting)
if (towardStart)
expanding = (nonAnchor <= fSelAnchor);
else
expanding = (nonAnchor >= fSelAnchor);
else
expanding = TRUE;
goToPos = nonAnchor;
if (!expanding)
if (towardStart)
{
newEnd = goToPos;
while ((goToPos > fSelAnchor) && ((!WordBounds(goToPos, newStart, newEnd)) || (newEnd + 1 >= nonAnchor)))
goToPos = newStart - 1;
if (goToPos <= fSelAnchor)
{
expanding = TRUE;
goToPos = fSelAnchor;
}
else
goToPos = newEnd + 1;
}
else //!towardStart
{
newStart = goToPos;
while ((goToPos < fSelAnchor) && ((!WordBounds(goToPos, newStart, newEnd)) || (newStart <= nonAnchor)))
goToPos = newEnd + 1;
if (goToPos >= fSelAnchor)
{
expanding = TRUE;
goToPos = fSelAnchor;
}
}
if (expanding)
if (towardStart)
{
i = goToPos;
newStart = goToPos;
while ((goToPos > 0) && ((!WordBounds(goToPos, newStart, newEnd)) || (newStart >= i)))
--goToPos;
goToPos = (short)Min(goToPos, newStart);//!!! long->short
}
else //!towardStart
{
newEnd = goToPos;
i = (**fHTE).teLength - 1;
while ((goToPos < i) &&!WordBounds(goToPos + 1, newStart, newEnd))
++goToPos;
goToPos = (short)Max(goToPos, newEnd) + 1;//!!! long->short
}
}
else if (event->fShiftKey || ((**fHTE).selStart == (**fHTE).selEnd)/*& ((ch == chLeft) || (ch ==
chRight))*/)
{
if (towardStart)
i = -1;
else
i = +1;
goToPos = (short)Min(Max(nonAnchor + i, 0), (**fHTE).teLength);//!!! long->short
}
else /*selStart != selEnd && ((ch == chLeft) || (ch ==
chRight))*/
{
if (towardStart)
goToPos = (**fHTE).selStart;
else
goToPos = (**fHTE).selEnd;
}
HUnlock((Handle)fHTE);
}
//################
handledCharacter = TRUE;
//################
if (handledCharacter)
{
if (selecting)
this->SetSelection((short)Min(goToPos, fSelAnchor), (short)Max(goToPos, fSelAnchor), kRedraw);//!!! long->short
else
this->SetSelection(goToPos, goToPos, kRedraw);
}
else
{
TEKey(ch, fHTE);
if (selecting)
this->SetSelection((short)Min((**fHTE).selStart, fSelAnchor), (short)Max((**fHTE).selEnd, fSelAnchor), kRedraw);//!!! long->short
else if ((**fHTE).selStart == (**fHTE).selEnd)
fSelAnchor = (**fHTE).selStart;
}
this->ScrollSelectionIntoView();
//################
}
else if (fAcceptsChanges && this->Focus())
{
// Check max size for text, and that we're not running out of memory
if ((ch != chBackspace) && (ch != chFwdDelete) && ((**fHTE).selStart == (**fHTE).selEnd))
if (((fMaxChars - GetHandleSize(fText)) < 1) || MemSpaceIsLow())
{
StdAlert(phTooManyChars);
// exit(DoKeyCommand); // Flush further keystrokes
return;
}
// Pass the character to the typing command, creating a new one if necessary
needNewCommand = (fTypingCommand == NULL);
if (!needNewCommand)
needNewCommand = fTypingCommand->fCompleted;
if (needNewCommand)
{
aTypingCommand = this->DoMakeTypingCommand(ch);
fTypingCommand = aTypingCommand;
this->PostCommand(aTypingCommand);
}
else
{
fTypingCommand->AddCharacter(ch);
/* Once you're typing (first character already processed) collecting subsequent
characters really shouldn't affect the menus unless you're keeping a character
count in them or something that depends on the aggregate of the characters you've
typed. The TextStyle for the first character would certainly apply to subsequent
characters. So, this is one ideal place to say that the event _DOES NOT_ affect
the menus. If the menus are already invalid they will stay so, but if they are
valid then there is no need to invalidate them in the character collection process.
When the user terminates the addition of characters with another event, the menus
will be setup from that event. If you really feel you must, then you can always
override, call inherited and then set event->fAffectMenus back to true. (Rhymes with
rue) */
event->fAffectsMenus = FALSE;
}
handledCharacter = TRUE;
}
}
if (fIdleFreq == kMaxIdleTime)
this->SetIdleFreq(0); /* Idle ASAP, since someone may somehow set
an insertion point and want it to flash.
(the idle time will be reset to match the
caret time in doidle.)*/
}
if (!handledCharacter)
inherited::DoKeyCommand(event);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::SetSelection(short NewSelStart,
short NewSelEnd,
Boolean redraw)
{
if (redraw && this->Focus())
{
TESetSelect(Max(NewSelStart, 0), Min(NewSelEnd, (**fHTE).teLength), fHTE);
this->SynchView(TRUE);
}
else
SetSelect((short)Max(NewSelStart, 0), (short)Min(NewSelEnd, (**fHTE).teLength), fHTE);//!!! long->short
if (NewSelStart == NewSelEnd)
fSelAnchor = NewSelStart;
fSpecsChanged = TRUE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TESelCommand
pascal TTECommand* TTEView::DoMakeEditCommand(CmdNumber aCmdNumber)
{
TTECommand * aTECommand = NULL;
switch (aCmdNumber)
{
case cCut:
case cCopy:
aTECommand = new TTECutCopyCommand;
((TTECutCopyCommand*)aTECommand)->ITECutCopyCommand(this, aCmdNumber);
break;
case cPaste:
aTECommand = new TTEPasteCommand;
((TTEPasteCommand*)aTECommand)->ITEPasteCommand(this);
break;
case cClear:
aTECommand = new TTECommand;
aTECommand->ITECommand(this, aCmdNumber, TRUE);
break;
}
return aTECommand;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal TTEStyleCommand* TTEView::DoMakeStyleCommand(const TextStyle& aStyle,
CmdNumber itsCmdNumber,
short itsMode)
{
TTEStyleCommand * aTEStyleCommand = new TTEStyleCommand;
aTEStyleCommand->ITEStyleCommand(this, aStyle, itsCmdNumber, itsMode);
return aTEStyleCommand;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal TTETypingCommand* TTEView::DoMakeTypingCommand(short ch)
{
TTETypingCommand * aTypingCommand = new TTETypingCommand;
aTypingCommand->ITETypingCommand(this, ch);
return aTypingCommand;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TESelCommand
pascal void TTEView::DoMenuCommand(CmdNumber aCmdNumber)// override
{
long nChars;
ResType dataType = '%%%%';
switch (aCmdNumber)
{
case cCut:
case cCopy:
case cClear:
this->PostCommand(this->DoMakeEditCommand(aCmdNumber));
break;
case cPaste:
//!!! dataType is never used by GetDataToPaste. Should it be a parameter?
nChars = gClipboardMgr->GetDataToPaste(NULL, dataType);
if (nChars < 0)
{
#if qDebug
ProgramBreak("Couldn't get data to paste");// ???
#endif
}
else
{
if (nChars - ((*fHTE)->selEnd - (*fHTE)->selStart) > fMaxChars - GetHandleSize(fText))
StdAlert(phTooManyChars);
else
this->PostCommand(this->DoMakeEditCommand(aCmdNumber));
}
break;
case cSelectAll:
if (this->Focus())
{
TESetSelect(0, (**fHTE).teLength, fHTE);
this->DoneTyping();
fSpecsChanged = TRUE;
this->ScrollSelectionIntoView();
}
break;
default:
inherited::DoMenuCommand(aCmdNumber);
break;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::DoMouseCommand(VPoint& theMouse,
TToolboxEvent* event,
Point) // override
{
if (this->Focus() && this->IsVisible())
{
pCurrTEView = this; // So the global clikLoop routine can forward
this->DoneTyping(); // Mousedown terminates the Typing command
fSpecsChanged = TRUE;
TEClick(this->ViewToQDPt(theMouse), event->fShiftKey, fHTE);
// …force a re-focus b/c the focusing in ClikLoop clips down to the destrect.
if (this->IsFocused())
this->InvalidateFocus();
if (fIdleFreq == kMaxIdleTime)
this->SetIdleFreq(0); // Idle ASAP
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::DoneTyping(void)
{
if (fTypingCommand != NULL)
fTypingCommand->CompleteTyping();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEPrint
pascal void TTEView::DoSetPageOffset(const VPoint& coord)// override
{
inherited::DoSetPageOffset(coord);
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
if (coord[vhs] == 0)
gPageOffset[vhs] = gPageOffset[vhs] + fInset[topLeft][vhs];
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::DoSetupMenus(void) // override
{
Boolean manyChars;
inherited::DoSetupMenus();
manyChars = (**fHTE).selStart < (**fHTE).selEnd;
if (!MemSpaceIsLow())
{
if (fAcceptsChanges) // One way or another, we can paste text
gClipboardMgr->CanPaste('TEXT'); // If styles exist, all the better
Enable(cCopy, manyChars);
}
Enable(cSelectAll, (**fHTE).teLength > 0);
/* We enable Cut even if space is low, since it's nice to be able to rescue some of
the stuff you have to delete even if space is low. Note that it is possible to
get into the "can't do any commands" situation as a result. You should be able
to close and save the big document, then save the rescued text elsewhere, however. */
Enable(cCut, manyChars && fAcceptsChanges);
Enable(cClear, manyChars && fAcceptsChanges);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::Draw(const VRect& area) // override
{
Rect QDArea;
Boolean hideSelection;
hideSelection = (gPrinting || gDrawingPictScrap) && ((Boolean)(**fHTE).active);
if (hideSelection)
{
// …prevent selection from being drawn.
#if qDebug
UseTempRgn("TTEView.Draw");
#endif
GetClip(gTempRgn);
ClipRect(gZeroRect);
TEDeactivate(fHTE);
SetClip(gTempRgn);
}
this->ViewToQDRect(area, QDArea);
TEUpdate(QDArea, fHTE); /* normal screen update handled by TextEdit
directly */
if (hideSelection)
{
GetClip(gTempRgn);
ClipRect(gZeroRect);
TEActivate(fHTE);
SetClip(gTempRgn);
#if qDebug
DoneWithTempRgn();
#endif
}
inherited::Draw(area);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::ExtractStyles(TEStyleHandle& theStyles,
STHandle& theElements)
{
theStyles = GetStylHandle(fHTE);
theElements = (**theStyles).styleTab;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal Handle TTEView::ExtractText(void)
{
return fText;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::GetPrintExtent(VRect& printExtent)// override
{
inherited::GetPrintExtent(printExtent);
printExtent[topLeft] += fInset[topLeft];
printExtent[botRight] -= fInset[botRight];
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::GetSelectionString(Str255& selection)
//!!! Modelled after TEditText.GetText
{
short start;
short length;
Handle theChars;
selection = "";
theChars = fText;
if ((theChars != NULL) && (fHTE != NULL))
{
start = (**fHTE).selStart;
length = (**fHTE).selEnd - start;
length = (short)Min(255, length); //!!! long->short
if (length > 0)
{
selection[0] = ((char)(length));
BlockMove((Ptr)((*theChars) + start), (Ptr)(&selection + 1), length);
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEClipboard
pascal long TTEView::GivePasteData(Handle aDataHandle,
ResType dataType)// override
{
short oldStart;
short oldEnd;
long aSize = 0;
Handle aHandle = NULL;
OSErr err;
Boolean savedPerm = FALSE;
FailInfo fi;
SignedByte savedState;
VOLATILE(aHandle);
if (fi.Try())
{
if (dataType == 'TEXT')
{
aSize = GetHandleSize(fText);
if (aDataHandle != NULL)
{
SetPermHandleSize(aDataHandle, aSize);// Don't forget. This can fail
BlockMove((*fText), (*aDataHandle), aSize);
}
}
else if (dataType == 'styl')
{
if (fStyleType == kWithStyle)
if (!SpaceForStyles(0, MAXINT))
Failure(noErr, 0); // We'll accept this error in worst case
else
{
oldStart = (**fHTE).selStart;
oldEnd = (**fHTE).selEnd;
SetSelect(0, MAXINT, fHTE);
aHandle = (Handle)GetStylScrap(fHTE);
SetSelect(oldStart, oldEnd, fHTE);
if (aHandle != NULL)
{
aSize = GetHandleSize(aHandle);
if (aDataHandle != NULL)
{
savedPerm = PermAllocation(TRUE);
// Try to prevent fragmentation, in case can't move while we're copying it!
savedState = LockHandleHigh(aHandle);
// Copy styles into user-supplied handle
err = PtrToXHand((*aHandle), aDataHandle, aSize);
HSetState(aHandle, savedState);// Okay for it to move again
savedPerm = PermAllocation(savedPerm);
if (err != noErr) // Maybe enough for one copy, but not two!
Failure(phStylesTooBig, phStylesTooBig + msgAlert);
}
aHandle = DisposeIfHandle(aHandle);
}
else if (aDataHandle != NULL)// Hmm. There _was_ enough memory, but the
Failure(phStylesTooBig, phStylesTooBig + msgAlert);/* …heap is probably pretty
fragmented */
}
}
else
Failure(noTypeErr, 0);
FailSpaceIsLow();
fi.Success();
}
else // Recover
{
aHandle = DisposeIfHandle(aHandle);
fi.ReSignal();
}
return aSize;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
//!!! Put this routine somewhere else
pascal Boolean IsTEFeatureFlagAvailable(void)
// TEFeatureFlag is only available as of System 6.0.5 and better, TE version 4 and better
{
return (gConfiguration.systemVersion >= 0x605) && (gConfiguration.teVersion >= gestaltTE4);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEOpen
pascal void TTEView::MakeTERecord(void)
{
TEHandle anHTE;
GrafPtr oldPort;
FailInfo fi;
TextStyle aTextStyle;
GetPort(oldPort);
SetPort(gWorkPort);
aTextStyle = fTextStyle;
SetPortTextStyle(aTextStyle);
Rect dest(fInset[topLeft], fSize - fInset[botRight]);
if (fStyleType == kWithStyle)
anHTE = TEStylNew(dest, dest); // Open a styled record if requested
else
anHTE = TENew(dest, dest); // …otherwise, do it the old way
SetPort(oldPort);
if (fi.Try()) // In case we couldn't create the TEHandle.
{
FailNIL(anHTE); // Make sure we actually created one
fHTE = anHTE; // We did, so save off TE handle
gDefClikLoopProc = (ProcPtr)(**anHTE).clikLoop;// Just in case we want to restore it…
// Note that the system call SetClikLoop
// _cannot_ be used to set the clikProc of
// the TERecord. This is because the default
// clikproc does not follow the Pascal Parameter
// passing conventions that this procedure expects.
this->SetJustification(fJustification, kDontRedraw);// Set justification to requested value
this->ChangeWrap(fAutoWrap, FALSE); // Install auto wrap (or CR only)
FailNoReserve(); // Got to have some reserve tank
fi.Success();
}
else // Recover
{
this->Free();
fi.ReSignal();
}
this->BeInPort(this->GetGrafPort()); // Associate with real port
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal short TTEView::OffsetToLine(short offset)
{
TERec & theTERec = **fHTE;
if (theTERec.nLines <= 1)
return 0;
else
{
short i = theTERec.nLines - 1;
while (theTERec.lineStarts[i] > offset)
--i;
return i;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal short TTEView::OffsetToLineStart(short offset)
{
if ((**fHTE).nLines <= 1)
return 0;
else
{
short i = this->OffsetToLine(offset);
return (**fHTE).lineStarts[i];
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal short TTEView::OffsetToLineEnd(short offset)
{
TERec & theTERec = **fHTE;
if (theTERec.nLines <= 1)
return theTERec.teLength;
else
{
short i = theTERec.nLines - 1;
while (theTERec.lineStarts[i] > offset)
--i;
if (i < theTERec.nLines - 1)
return (theTERec.lineStarts[i + 1] - 1);
else
return theTERec.teLength;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::OffsetToPt(short offset, VPoint& itsPoint)
{
short height;
Point thePoint;
TextStyle theStyle;
short ascent;
TEGetStyle(offset, theStyle, height, ascent, fHTE);
if ((**fHTE).teLength <= 0) /* Through System 6.0.4 TE TEGetPoint returns
bogus numbers when the character count is
0. */
SetPt(thePoint, (short)fInset.left, (short)fInset.top);//!!! VCoordinate->short
else
thePoint = TEGetPoint(offset, fHTE);
thePoint.v = thePoint.v - height + ascent;
this->QDToViewPt(thePoint, itsPoint);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal short TTEView::PtToOffset(const VPoint& aPoint)
{
return TEGetOffset(this->ViewToQDPt(aPoint), fHTE);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::RecalcText(void)
{
TECalText(fHTE);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::ResignedWindowTarget(void) // override
{
/* if (fHTE && IsTEFeatureFlagAvailable())
{
TEFeatureFlag(teFOutlineHilite, TEBitSet, fHTE);
}
*/
// this->DoHighlightSelection(hlOn,hlDim);
this->SetActive(FALSE);
this->DoneTyping();
fSpecsChanged = TRUE;
inherited::ResignedWindowTarget();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::ResignedApplicationTarget(void) // override
{
/*
if (fHTE && IsTEFeatureFlagAvailable())
{
TEFeatureFlag(teFOutlineHilite, TEBitSet, fHTE);
}
this->SetActive(FALSE);
this->DoneTyping();
fSpecsChanged = TRUE;
*/
inherited::ResignedApplicationTarget();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::Resize(const VPoint& newSize,
Boolean invalidate) // override
{
VPoint oldSize(fSize);
inherited::Resize(newSize, invalidate);
if (fHTE != NULL)
{
Rect r(fInset[topLeft], fSize - fInset[botRight]);
Boolean needCalText = (r.right != (**fHTE).destRect.right);
this->StuffTERects(r);
if (needCalText)
{
this->RecalcText();
this->SynchView(kDontRedraw);
short actualJust = GetActualJustification(fJustification);
if (invalidate && ((fAutoWrap && (fSize != oldSize))
|| ((actualJust == teFlushRight) || (actualJust == teCenter))))
this->ForceRedraw();
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::ScrollSelectionIntoView(void)
{
VRect selectionRect;
VPoint minToSee;
VRect visRect;
VRect vSelectionRect;
/* ??? should we have an option to walk the superviews, scrolling as many scrollers as necessary
to reveal the selection? */
if ((this->GetScroller(FALSE) != NULL) && this->Focus())// Can't scroll selection if we don't have
{
// … a scroller!
if (fIdleFreq == kMaxIdleTime)
this->SetIdleFreq(0); // Idle ASAP
this->GetVisibleRect(visRect);
this->CalcSelLoc(selectionRect);
#if qDebugMsg
if (gIntenseDebugging)
{
fprintf(stderr, "Visible Rect was: ");
WriteVRect(visRect);
fprintf(stderr, "; Sel Rect was: ");
WriteVRect(selectionRect);
fprintf(stderr, "\n");
}
#endif
if (!visRect.Contains(selectionRect))
{
/* Scroll the selection into view. accounting for the user's preference for how much to
jump at a time with fMinAhead. */
minToSee = VPoint(selectionRect.Length(vSel), Min(fMinAhead, fSize.h - selectionRect.left));
#if qDebug
if (gIntenseDebugging)
{
WrLblVRect("RevealRect: r", selectionRect);
WrLblVPt(", minToSee", minToSee);
fprintf(stderr, "\n");
}
#endif
this->RevealRect(selectionRect, minToSee, kRedraw);
this->Focus(); // Refocus in newly-scrolled position. Why???
// does our caller have a dependency on this?
}
}
else if (!fAutoWrap && (fHTE != NULL))
TESelView(fHTE);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::SetJustification(short newJust,
Boolean redraw)
{
TESetJust(newJust, fHTE);
fJustification = newJust;
if (redraw)
this->ForceRedraw();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::SetOneStyle(short theStart,
short theEnd,
short theMode,
const TextStyle& theStyle,
Boolean redraw)
{
short saveStart;
short saveEnd;
FontInfo fInfo;
TextStyle newStyle;
short theFontHeight;
this->InvalidateFocus(); // ??? THIS SHOULDN'T BE NECESSARY! ???
this->Focus();
if (fStyleType == kWithStyle)
{
saveStart = (**fHTE).selStart;
saveEnd = (**fHTE).selEnd;
SetSelect(theStart, theEnd, fHTE);
TESetStyle(theMode, theStyle, redraw, fHTE);
SetSelect(saveStart, saveEnd, fHTE);
}
else
{
if (theMode == doAll)
newStyle = theStyle;
else
{
newStyle = fTextStyle;
if (((theMode) & doFont) != 0)
{
newStyle.tsFont = theStyle.tsFont;
KeyScript(Font2Script(newStyle.tsFont));// …keybd input system to match new font
}
if (((theMode) & doFace) != 0)
newStyle.tsFace = theStyle.tsFace;
if (((theMode) & doColor) != 0)
newStyle.tsColor = theStyle.tsColor;
if (((theMode) & addSize) != 0)
newStyle.tsSize = newStyle.tsSize + theStyle.tsSize;
else if (((theMode) & doSize) != 0)
newStyle.tsSize = theStyle.tsSize;
}
GetTextStyleFontInfo(newStyle, fInfo, theFontHeight);/* Need to get font's height and
ascent. */
{
TERec & theTERec = **fHTE;
theTERec.txSize = newStyle.tsSize;
theTERec.txFont = newStyle.tsFont;
theTERec.txFace = newStyle.tsFace;
theTERec.fontAscent = fInfo.ascent;
theTERec.lineHeight = theFontHeight;
}
SetIfColor(newStyle.tsColor);
fTextStyle = newStyle;
}
if (TRUE /* (fStyleType == kWithoutStyle) || (theStart != theEnd) */)
{
this->RecalcText();
this->SynchView(redraw && (fStyleType == kWithStyle));
if (redraw && (fStyleType == kWithoutStyle))
this->ForceRedraw();
}
fSpecsChanged = TRUE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::SetText(const Str255& theText)
{
if (fHTE != NULL) // If we're replacing text, styles are kaput
{
Handle theTextHandle;
Str255 tempString = theText;
FailOSErr(PtrToHand((Ptr)&(tempString[1]), theTextHandle, tempString.Length()));
this->StuffText(theTextHandle);
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::ShowReverted(void) // override
{
this->RecalcText();
fLastHeight = 0;
fLastWidth = 0;
inherited::ShowReverted();
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal Boolean TTEView::SpaceForStyles(long rangeStart,
long rangeEnd)
{
FailInfo fi;
Handle h;
Boolean result = FALSE;
if (fi.Try())
{
h = NewPermHandle(TENumStyles(rangeStart, rangeEnd, fHTE) * sizeof(ScrpSTElement) + 2);
h = DisposeIfHandle(h); // Release memory back to the system
result = TRUE;
fi.Success();
}
else // Recover. Don't resignal in this case
StdAlert(phStylesTooBig);
return result;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::StuffStyles(TEStyleHandle theStyles,
STHandle theElements)
{
LHHandle oldLineHeights;
NullStHandle theNullStyles;
StScrpHandle theScrpHandle;
if ((fStyleType == kWithStyle) && (fHTE != NULL))
{
{
TEStyleHandle oldStyles = GetStylHandle(fHTE);
TEStyleRec & theTEStyleRec = **oldStyles;
STHandle oldElements = theTEStyleRec.styleTab;
oldLineHeights = theTEStyleRec.lhTab;
theNullStyles = theTEStyleRec.nullStyle;
theScrpHandle = (**(theTEStyleRec.nullStyle)).nullScrap;
oldElements = (STHandle)DisposeIfHandle((Handle)oldElements);
}
{
TEStyleRec & theTEStyleRec = **theStyles;
theTEStyleRec.styleTab = theElements; // Replace STElements handle
theTEStyleRec.lhTab = oldLineHeights; // Replace line heights table handle
theTEStyleRec.nullStyle = theNullStyles;// Replace null style handle
(**(theTEStyleRec.nullStyle)).nullScrap = theScrpHandle;
theTEStyleRec.teRefCon = ((long)this); // store ourselves as the refcon reference
}
// NOTE!! SetStylHandle will dispose of oldStyles for us!
SetStylHandle(theStyles, fHTE);
this->RecalcText();
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::StuffText(Handle theText)
{
if (fHTE) // If we're replacing text, styles are kaput
{
long textLength = GetHandleSize(theText); // Check size of new text
if (textLength > fMaxChars)
{
#if qDebug
ProgramBreak("Text size exceeds maximum for this view");
#endif
Failure(minErr, 0); // ??? Assign a message
}
if (fSavedTEHandle != theText)
{
fSavedTEHandle = DisposeIfHandle(fSavedTEHandle);/* …we have no choice but to dispose
it */
fSavedTEHandle = (**fHTE).hText; // Save existing handle
}
(**fHTE).hText = theText; // Install new handle
fText = theText; // Make a local copy, too
(**fHTE).teLength = (short)textLength; // Tell TE how long we are //!!! long->short
if (fStyleType == kWithStyle) // Fix for styled TE. Yuk.
{
TEStyleHandle styles = GetStylHandle(fHTE);
{
TEStyleRec& aTEStyleRec = **styles;
aTEStyleRec.runs[1].startChar = (**fHTE).teLength + 1;
aTEStyleRec.nRuns = 1;
aTEStyleRec.nStyles = 1;
// Thanks to map
}
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::StuffTERects(const Rect& newTERect)
{
FontInfo aFontInfo;
Rect localRect;
GetFontInfo(aFontInfo);
localRect = newTERect;
localRect.right = (short)Max(localRect.right, localRect.left + aFontInfo.widMax);/* IM says must be at least one char wide //!!! long->short
and suggests 20 pixels. We just check for one char. ??? can this change in newer TE Vers? */
(**fHTE).destRect = localRect;
(**fHTE).viewRect = localRect;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::SynchView(Boolean redraw)
{
const short kInsertionBarWidth = 1; /* We all _KNOW_ an insertion bar is one
pixel wide right? */
VRect aRect;
long theHeight;
long theWidth;
Boolean doRealWidth;
theHeight = this->CalcRealHeight();
doRealWidth = (fSizeDeterminer[hSel] == sizeVariable) &&!fStyleType &&!fAutoWrap;
if (doRealWidth)
theWidth = this->CalcRealWidth() + kInsertionBarWidth * 2;
if ((fLastHeight != theHeight) || (doRealWidth && (fLastWidth != theWidth)))
{
if (doRealWidth)
fLastWidth = theWidth; /* Width is expensive to calculate. Cache for
CalcMinSize */
this->AdjustSize(); // may need to grow view
fLastHeight = theHeight; // Remember new height value
}
if (redraw && this->Focus())
/* First, make sure selection is visible (this conveniently focuses). Then,
repair any extra feedback which TextEdit may have mashed. */
{
this->ScrollSelectionIntoView();
this->DoHighlightSelection(hlOff, fHLDesired);
if (fPrintHandler != NULL)
{
this->GetDrawableRect(aRect);
this->DoDrawPrintFeedback(aRect);
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TENonRes
pascal void TTEView::WriteToDeskScrap(void) // override
{
Handle aHandle;
FailOSErr(gClipboardMgr->PutDeskScrapData('TEXT', fText));
if ((fStyleType == kWithStyle) && this->SpaceForStyles(0, MAXINT))
{
SetSelect(0, MAXINT, fHTE);
aHandle = (Handle)(GetStylScrap(fHTE));
FailNIL(aHandle);
FailOSErr(gClipboardMgr->PutDeskScrapData('styl', aHandle));
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::SetActive(Boolean state)
{
if ((fHTE != NULL) && this->Focus()) // Try to focus because TEActivate/TEDeactivate may draw
if (state)
TEActivate(fHTE);
else
{
TEDeactivate(fHTE);
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal void TTEView::SetEnable(Boolean state)
{
if (state && (fIdleFreq == kMaxIdleTime))
this->SetIdleFreq(0); // Get correct idle set ASAP
inherited::SetEnable(state);
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal Boolean TTEView::WantToBecomeTarget(void)// override
{
return TRUE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment TERes
pascal Boolean TTEView::WordBounds(short charPos,
short& wordStart,
short& wordEnd)
{
OffsetTable offs;
short i;
wordStart = charPos;
wordEnd = charPos;
if ((charPos < 0) || (charPos > (**fHTE).teLength - 1))
return FALSE;
do
{
i = CharByte((*fText), charPos++);
} while ((i == smFirstByte) || (i == smMiddleByte)); // while ((i != smSingleByte) && (i != smLastByte));
FindWord((*fText), (**fHTE).teLength, --charPos, TRUE, NULL, offs);
wordStart = (short)Min(offs[0].offFirst, offs[0].offSecond - 1);//!!! long->short
wordEnd = (short)Max(offs[0].offFirst, offs[0].offSecond - 1);//!!! long->short
return ((wordStart < wordEnd) || (CharType((*fText), wordStart) % 8 != smCharPunct));
}
//--------------------------------------------------------------------------------------------------
#pragma segment TEFields
pascal void TTEView::Fields(TObject* obj) // override
{
obj->DoToField("TTEView", NULL, bClass);
obj->DoToField("fHTE", &fHTE, bTEHandle);
obj->DoToField("fText", &fText, bHandle);
obj->DoToField("fSavedTEHandle", &fSavedTEHandle, bHandle);
obj->DoToField("fInset", &fInset, bRect);
obj->DoToField("fKeyCmdNumber", &fKeyCmdNumber, bCmdNumber);
obj->DoToField("fMaxChars", &fMaxChars, bInteger);
obj->DoToField("fLastHeight", &fLastHeight, bLongInt);
obj->DoToField("fLastWidth", &fLastWidth, bLongInt);
obj->DoToField("fTypingCommand", &fTypingCommand, bObject);
obj->DoToField("fTextStyle", &fTextStyle, bTextStyle);
obj->DoToField("fJustification", &fJustification, bInteger);
obj->DoToField("fAcceptsChanges", &fAcceptsChanges, bBoolean);
obj->DoToField("fStyleType", &fStyleType, bBoolean);
obj->DoToField("fAutoWrap", &fAutoWrap, bBoolean);
obj->DoToField("fFreeText", &fFreeText, bBoolean);
obj->DoToField("fSpecsChanged", &fSpecsChanged, bBoolean);
obj->DoToField("fLastLine", &fLastLine, bInteger);
obj->DoToField("fLastPageBreak", &fLastPageBreak, bInteger);
obj->DoToField("fControlChars", &fControlChars, bHexLongInt);
obj->DoToField("fMinAhead", &fMinAhead, bInteger);
inherited::Fields(obj);
}